/* -*- Mode: c; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/*
  RefObject (http://code.google.com/p/refobject/)
  Copyright (C) 2010-2011 MIURA Shirow (sharow)
*/

#include <string.h>             /* for memcpy */

#include "RefByteArrayInternal.h"
#include "RefModuleInternal.h"
#include <RefObject/RefAllocator.h>


typedef struct {
    unsigned char *mByteArray;
	int mLength;
    int mByteArrayWasDuplicated;
    RefObject *mRefAllocator;
} RefByteArray;

static RefTypeObject *gByteArrayTypeObject = NULL;

RefTypeObject **
RefByteArray_GetTypeObject(void)
{
    return &gByteArrayTypeObject;
}

int
RefByteArray_IsValid(RefObject *aRefObject)
{
    return (RefObject_GetTypeObject(aRefObject) == &gByteArrayTypeObject);
}

static void
RefByteArray_Destructor(RefObject *aRefObject)
{
    RefByteArray *bytearray;
    RefObject *refallocator;
    bytearray = RefObject_GetObject(aRefObject);
    refallocator = bytearray->mRefAllocator;
    if (bytearray->mByteArrayWasDuplicated) {
        RefAllocator_Free(refallocator, bytearray->mByteArray);
    }
    RefAllocator_Free(refallocator, aRefObject);
    RefObject_DecRef(refallocator);
}

static RefObject *
RefByteArray_Create(unsigned char *aByteArray, int aLength,
                    int aDuplicated, RefObject *aRefAllocator)
{
    RefObject *refobj;
    RefByteArray *bytearray;
    refobj = RefAllocator_Alloc(aRefAllocator, RefObject_SizeOf() + sizeof(*bytearray));
    bytearray = RefObject_Construct(refobj, &gByteArrayTypeObject, RefByteArray_Destructor);
    bytearray->mByteArray = aByteArray;
    bytearray->mLength = aLength;
    bytearray->mByteArrayWasDuplicated = aDuplicated;
    bytearray->mRefAllocator = aRefAllocator;
    RefObject_IncRef(aRefAllocator);
    return refobj;
}

RefObject *
RefByteArray_CreateDuplicate(unsigned char *aByteArray, int aLength)
{
    return RefByteArray_CreateDuplicateWithAllocator(aByteArray, aLength,
                                                     RefModule_GetSingletonAllocator());
}

RefObject *
RefByteArray_CreateShallow(unsigned char *aByteArray, int aLength)
{
    return RefByteArray_CreateShallowWithAllocator(aByteArray, aLength,
                                                   RefModule_GetSingletonAllocator());
}

RefObject *
RefByteArray_CreateDuplicateWithAllocator(unsigned char *aByteArray, int aLength,
                                          RefObject *aRefAllocator)
{
    unsigned char *bytearray;
    if (aLength >= 0 && aByteArray && aRefAllocator && RefAllocator_IsValid(aRefAllocator)) {
    } else {
        return NULL;
    }
    bytearray = RefAllocator_Alloc(aRefAllocator, sizeof(*aByteArray) * aLength);
    memcpy(bytearray, aByteArray, aLength);
    return RefByteArray_Create(bytearray, aLength, 1, aRefAllocator);
}

RefObject *
RefByteArray_CreateShallowWithAllocator(unsigned char *aByteArray, int aLength,
                                        RefObject *aRefAllocator)
{
    if (aLength >= 0 && aByteArray && aRefAllocator && RefAllocator_IsValid(aRefAllocator)) {
    } else {
        return NULL;
    }
    return RefByteArray_Create(aByteArray, aLength, 0, aRefAllocator);
}

unsigned char *
RefByteArray_AsByteArray(RefObject *aRefObject)
{
    return ((RefByteArray *)RefObject_GetObject(aRefObject))->mByteArray;
}

int
RefByteArray_GetLength(RefObject *aRefObject)
{
    return ((RefByteArray *)RefObject_GetObject(aRefObject))->mLength;
}

